package artibella.media.audio 
{
	import caurina.transitions.properties.SoundShortcuts;
	import caurina.transitions.Tweener;
	
	import flash.errors.IllegalOperationError;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundLoaderContext;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;
	
	
	/**
	 * ...
	 * @author pbordachar
	 */
	
	public class SoundLibrary
	{
		private static var _instance:SoundLibrary;
		
		private var _tab:Vector.<SoundObject>;
		private var _dict:Dictionary;
		
		public function SoundLibrary( c:PrivateClass = null ) 
		{
			if( !c ) {
				throw new IllegalOperationError( 'Error : singleton pattern' );
			} else {

				_tab = new Vector.<SoundObject>();
				_dict = new Dictionary(true);
				
				SoundShortcuts.init();
			}
		}
		
		public static function get instance():SoundLibrary
		{
			return _instance || ( _instance = new SoundLibrary( new PrivateClass() ) );
		}
		
		///////  A D D
		
		public function addLibrarySound( kls:*, id:String ):Boolean
		{
			for (var i:int = 0; i < _tab.length; i++)
			{
				if ( _tab[i].name == id) return false;
			}
			
			var obj:SoundObject = new SoundObject();
			var son:Sound = new kls();
			obj.name = id;
			obj.sound = son;
			obj.channel = new SoundChannel();
			
			_tab.push( obj );
			_dict[ id ] = obj;
			
			return true;
		}
		
		public function addExternalSound( u:String, id:String, buffer:int = 1000, checked:Boolean = false):Boolean
		{
			for (var i:int = 0; i < _tab.length; i++)
			{
				if ( _tab[i].name == id ) return false;
			}
			
			var obj:SoundObject = new SoundObject();
			var son:Sound = new Sound( new URLRequest( u ), new SoundLoaderContext( buffer, checked ) );			
			
			obj.name = id;
			obj.sound = son;
			obj.channel = new SoundChannel();
			
			_tab.push( obj );
			_dict[ id ] = obj;
			
			return true;
		}
		
		///////  R E M O V E
		
		public function removeSound( id :String):void
		{
			for (var i:int = 0; i < _tab.length; i++)
			{
				if ( _tab[i].name == id )
				{
					_tab[i] = null;
					_tab.splice(i, 1);
				}
			}
			delete _dict[ id ];
		}
		
		
		public function removeAllSounds():void
		{
			for (var i:int = 0; i < _tab.length; i++)
			{
				_tab[i] = null;
			}
			_tab = new Vector.<SoundObject>();
			_dict = new Dictionary(true);
		}
		
		/////// 
		
		public function playSound( id:String, vol:Number = 1, seek:int = 0, loops:int = 0):void
		{
			var obj:SoundObject = _dict[ id ];
			obj.volume = vol;
			obj.startTime = seek;
			obj.loops = loops;
			
			if ( obj.paused )
			{
				obj.channel = obj.sound.play( obj.position, obj.loops, new SoundTransform( obj.volume ) );
			}
			else
			{
				obj.channel =obj.sound.play( seek, obj.loops, new SoundTransform( obj.volume ) );
			}
			
			obj.paused = false;
		}
		
		public function stopSound( id:String ):void
		{
			var obj:SoundObject = _dict[ id ];
			obj.paused = true;
			obj.channel.stop();
			obj.position = obj.channel.position;
		}
		
		public function pauseSound( id:String ):void
		{
			var obj:SoundObject = _dict[ id ];
			obj.paused = true;
			obj.position = obj.channel.position;
			obj.channel.stop();
		}
		
		public function fadeSound( id:String, vol:Number = 0, d:Number = 1):void
		{
			var fadeChannel:SoundChannel = _dict[ id ].channel;
			Tweener.addTween( fadeChannel, { _sound_volume: vol, time: d, transition:"linear" } );
		}
		
		public function setSoundVolume( id:String, vol:Number ):void
		{
			var obj:SoundObject = _dict[ id ];
			var trans:SoundTransform = obj.channel.soundTransform;
			trans.volume = vol;
			obj.channel.soundTransform = trans;
		}
		
		public function getSoundVolume( id:String ):Number
		{
			return _dict[ id ].channel.soundTransform.volume;
		}
		
		public function getSoundPosition( id:String ):Number
		{
			return _dict[ id ].channel.position;
		}
		
		public function getSoundDuration( id:String ):Number
		{
			return _dict[ id ].sound.length;
		}
		
		///////
		
		public function getSoundObject( id:String ):Sound
		{
			return _dict[ id ].sound;
		}
		
		public function isSoundPaused( id:String ):Boolean
		{
			return _dict[ id ].paused;
		}
	
		public function isSoundPausedByAll( id:String ):Boolean
		{
			return _dict[ id ].pausedByAll;
		}
		
		/////// 
		
		public function playAllSounds( pausedByAll:Boolean = false ):void
		{
			for (var i:int = 0; i < _tab.length; i++)
			{
				var id:String = _tab[i].name;
				
				if ( pausedByAll )
				{
					if (_dict[ id ].pausedByAll)
					{
						_dict.pausedByAll = false;
						playSound( id );
					}
				}
				else
				{
					playSound( id );
				}
			}
		}
		
		public function stopAllSounds( pausedByAll:Boolean = true ):void
		{
			for (var i:int = 0; i < _tab.length; i++)
			{
				var id:String = _tab[ i ].name;
				
				if ( pausedByAll )
				{
					if ( !_dict[ id ].paused )
					{
						_dict[ id ].pausedByAll = true;
						stopSound( id );
					}
				}
				else
				{
					stopSound( id );
				}
			}
		}
		
		public function pauseAllSounds( pausedByAll:Boolean = true ):void
		{
			for (var i:int = 0; i < _tab.length; i++)
			{
				var id:String = _dict[ i ].name;
				
				if ( pausedByAll )
				{
					if ( !_dict[ i ].paused )
					{
						_dict[ i ].pausedByAll = true;
						pauseSound( id );
					}
				}
				else
				{
					pauseSound( id );
				}
			}
		}
		
		public function muteAllSounds():void
		{
			for (var i:int = 0; i < _tab.length; i++)
			{
				var id:String = _tab[ i ].name;
				setSoundVolume( id, 0 );
			}
		}
		
		public function unmuteAllSounds():void
		{
			for (var i:int = 0; i < _tab.length; i++)
			{
				var id:String = _tab[ i ].name;
				var obj:SoundObject = _dict[ id ];
				var trans:SoundTransform = obj.channel.soundTransform;
				trans.volume = obj.volume;
				obj.channel.soundTransform = trans;
			}
		}
		
		///////
		
		public function get sounds():Array
		{
			return _tab;
		}
		
		public function toString():String
		{
			return getQualifiedClassName( this ); // what for ?
		}
	}
}


/// - - -

class PrivateClass { }